package com.wn.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wn.common.api.Result;
import com.wn.common.api.enums.ResultCode;
import com.wn.common.jwt.JwtTemplate;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.concurrent.TimeUnit;

/**
 * @author yellow Docter
 * @date 2022 -11-09
 * @desc
 *  全局过滤器 进行 鉴权操作
 *
 *  1、获取请求的url、进行path的判断
 *  2、获取请求的携带的token
 *
 *  3、查看携带的token中的数据
 *  4、判断token是否过期没有
 *  5、放行
 *
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter {

    @Autowired
    private JwtTemplate jwtTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //webflux  gateway 基于webflux 进行集成
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //01 获取请求的 url
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        //服务器返回对象
        ServerHttpResponse response = exchange.getResponse();

        //02 拦截请求的url中携带的auth
//        if (path.contains("auth")){
//        }
        AntPathMatcher pathMatcher = new AntPathMatcher();
        //02 拦截 请求的url中存在 auth就可以
        boolean match = pathMatcher.match("/**/auth/**", path);
        System.out.println("match = " + match);
        if (match){
            //进行业务逻辑处理
            //03 拿到头信息
            String authorization = exchange.getRequest().getHeaders().getFirst("Authorization");

            if (StringUtils.isEmpty(authorization)){
                return  error(response);
            }
            //04 拿到token
            String token = authorization.replace("Bearer ", "");
            System.out.println("token = " + token);

            //05 校验token
            boolean verifyToken = jwtTemplate.verifyToken(token);
            if (!verifyToken){
                //token 校验失败
                log.info("校验失败");
                return  error(response);
            }

            //06 解析token
            String userId = (String) jwtTemplate.parseToken(token,"userId");
            //07 判断 token 是否过期没有
            String key = "SKMEMBER:USER_ID:" + userId;
            String redisToken = stringRedisTemplate.opsForValue().get(key);
            if (StringUtils.isEmpty(redisToken)){
                log.info("token 过期了....");
                return  error(response);
            }

            //08 修改 头信息
            ServerHttpRequest.Builder mutate = request.mutate();
            mutate.header("userId",userId);

            //09 续签
            stringRedisTemplate.expire(key,30, TimeUnit.MINUTES);
        }

        return chain.filter(exchange);
    }

    // 自动处理检查异常的注解
    @SneakyThrows
    private Mono<Void> error(ServerHttpResponse response)  {
        // 创建一个 返回结果
        Result<String> result = Result.fail(ResultCode.PERMISSION_NO_ACCESS);

        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes = objectMapper.writeValueAsBytes(result);

        //把 bytes写到内存中
        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);

        return response.writeWith(Mono.just(dataBuffer));
    }
}
